Bygg et image med Dockerfile
Her bygger du et image fra en Flask-app og prøver det med docker run. Du er ferdig når appen svarer og du har kontrollert at den lokale .env-filen holdes utenfor det nye imaget. Testappen krever verken GitHub eller et eksternt API.
Før du bygger
Du skal bygge et image og vise at en container fra imaget svarer. Du trenger installert Docker og må kunne starte og undersøke en container, som vist i Kjør og undersøk en container. Har du ingen Flask-app, bruker du testappen nedenfor. Arbeid i prosjektmappen på Linux-VM-en, der både app.py og eventuelle maler og andre prosjektfiler ligger.
Hvis prosjektet ligger i et kodearkiv, viser Git i terminalen hvordan du kloner det til VM-en. Du kan også opprette filene i VM-ens teksteditor. Bruk pwd og ls til å kontrollere at du står i riktig mappe. Ikke bygg fra en tom mappe eller fra Proxmox-vertens Shell.
Prøv først med en liten testapp
Har du ikke fått appen din over på VM-en ennå, kan du øve på Dockerfile med en minimal app. Lag en mappe med mkdir min-app og cd min-app, og lag app.py med nano:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Hei fra containeren!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Lag deretter requirements.txt og Dockerfile som vist under. Når byggingen virker, gjør du det samme med din egen app.
Opprett requirements.txt i samme mappe. Den lister Python-pakkene som skal installeres i imaget. For den enkle applikasjonen fra Flask 1, som bare bruker Flask, er innholdet:
Flask
Bruker appen andre tredjepartsbiblioteker, må de også stå der med riktige pakkenavn, for eksempel requests. Filer som .venv kopieres ikke for å installere pakkene; Docker installerer dem på nytt fra denne listen. Versjoner kan låses, for eksempel med pakkenavn==versjon, når du har kontrollert hvilke versjoner appen bruker.
Opprett også .dockerignore før første bygg. Den hindrer at lokale hemmeligheter, Git-historikk og det lokale Python-miljøet kopieres inn i imaget:
.env
.git
__pycache__/
.venv/
app-data/
Legg også .env i .gitignore hvis du bruker Git. Har ignoreringsfilene innhold fra før, legger du til manglende regler i stedet for å erstatte filene. Bruk .gitignore og hemmeligheter til å kontrollere sporingen før du deler kode.
Lag et image med Dockerfile
docker build lager pakken. docker run oppretter og starter en container fra pakken. Byggingen alene starter ikke applikasjonen. Se Level 0 hvis du trenger å skille image fra container igjen.
En Dockerfile beskriver trinnene Docker skal bruke for å bygge et image. Hver linje gjør noe bestemt:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
Docker utfører bygget trinnvis. COPY og RUN kan legge til filsystemlag, mens blant annet CMD beskriver hvordan containeren skal startes. Docker kan gjenbruke tidligere byggeresultater fra et mellomlager (build cache). Når et trinn må bygges på nytt, må også de etterfølgende trinnene kjøres på nytt.
Derfor kopierer vi requirements.txt alene før COPY . .: den tidkrevende installasjonen kommer før kildekoden, som endres ofte:
flowchart TB
L1["Basisimage: python:3.12-slim"] --> L2["Arbeidsmappe: /app"]
L2 --> L3["Kopier requirements.txt"]
L3 --> L4["Installer pakkene med pip"]
L4 --> L5["Kopier kildekoden"] COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
Hvis requirements.txt endres, må Docker installere pakkene på nytt. Det er ønsket: den nye pakken skal faktisk komme med i imaget. Hvis bare kildekoden endres, kan Docker bruke det ferdige installasjonslaget og bygge videre fra COPY . ..
Når Docker publiserer en port, videresender Docker trafikken til programmet inne i containeren. Programmet må derfor lytte på containerens nettverk, ikke bare på 127.0.0.1, som betyr “denne containeren”. Hvis programmet bare lytter på 127.0.0.1, kan ikke andre maskiner nå det gjennom Docker-porten.
Flask-eksempel
Flask må lytte på alle nettverksgrensesnitt (0.0.0.0) når den kjører i container. 0.0.0.0 betyr at Flask tar imot forespørsler på alle nettverkskort inne i containeren. Erstatt den eksisterende oppstartsblokken i app.py med:
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=False)
Dette er et øvingsoppsett med Flask sin utviklingsserver. Før løsningen brukes i produksjon, må den kjøres med en egnet WSGI-server; se Flask: produksjonsoppsett.
EXPOSE 5000 beskriver hvilken port appen bruker; det publiserer ikke porten alene. Det gjør -p 127.0.0.1:5000:5000 i kommandoen under. Bygg og start:
docker build -t min-app:latest .
docker run -d --name min-app -p 127.0.0.1:5000:5000 min-app:latest
docker logs -f min-app
Trykk Ctrl+C for å avslutte loggvisningen. Containeren fortsetter å kjøre.
Test fra VM-en selv:
curl http://127.0.0.1:5000
Du skal få tilbake innholdet fra appens hovedroute. I -p 127.0.0.1:5000:5000 betyr 127.0.0.1:5000 port 5000 på serveren, men bare for programmer på serveren selv. Det siste tallet er porten inne i containeren. Hvis det ikke virker, sjekk først docker ps, loggene og at porten er riktig publisert.
Med 127.0.0.1 foran er porten stengt mot nettverket, så ingen andre maskiner kan nå appen mens du bygger og tester. Det er en trygg standard for en app under utvikling. Uten 127.0.0.1 (-p 5000:5000) lytter porten på alle nettverkskortene til serveren. Det trenger du først når en annen maskin eller en proxy skal nå appen, i Level 3.
Kontrollpunkt: Eget image virker
curl http://127.0.0.1:5000 skal vise appens hovedside. For testappen er svaret Hei fra containeren!. Forklar hva docker build laget, og hva docker run startet. Ved feil leser du loggen før du går videre.
Kontroller at .env holdes utenfor
Du trenger ikke en ekte nøkkel for å kontrollere dette. Hvis prosjektet ikke allerede har en .env, kan du lage den med PIGGY_TEST=ufarlig_testverdi. Behold en eksisterende fil; ikke skriv over verdiene dine.
- Se at
.envstår i både.dockerignoreog.gitignore. - Bruker du Git, kjør kontrollene i .gitignore-øvelsen. En ignorert fil skal heller ikke være sporet fra før.
- Bygg imaget på nytt og kontroller denne filstien uten å skrive ut innhold:
docker build -t min-app:latest .
docker run --rm --entrypoint sh min-app:latest -c 'test ! -e /app/.env && echo ".env finnes ikke i /app"'
Forventet resultat er .env finnes ikke i /app. Kommer meldingen ikke, undersøk ignoreringsfilen før du deler imaget. Dette kontrollerer filstien i det nye imagets ferdige filsystem. Det friskmelder ikke gamle images, andre hemmelighetsfiler eller verdier skrevet direkte i kode eller Dockerfile. Bytt en ekte nøkkel først hvis den tidligere er delt.
Hvis byggingen eller appen feiler
Ved ModuleNotFoundError kontrollerer du requirements.txt og bygger på nytt. Feiler nedlasting av basisimage eller Python-pakker, test nettverket med Feilsøkingsmetode. Ved manglende HTTP-svar leser du docker logs min-app og kontrollerer Flask-adresse og portkobling.
Neste steg
Vis appens svar og kontrollen av .env. Forklar hva Dockerfile beskriver, hva byggingen lager, og hva docker run starter. Fortsett med Docker - Publisere applikasjon. Vil du beskrive oppstart og oppdatering i en Compose-fil, er Kjør og oppdater appen med Compose en valgfri fordypning.
Compose og oppdatering står nå på Kjør og oppdater appen med Compose.
Lagring forklares i Bevar data utenfor containeren; Compose-anvendelsen står på Kjør og oppdater appen med Compose.
API-oppskriften står nå på Miljøvariabel og API-nøkkel og er valgfri.